#include "engine.h"
#include "scene.h"
#include "core/log.h"

DEFINE_ENTITY_ICON(scene_t,entity_t,"Icons\\world.png");
PROPERTY_BINDING_BEGIN(scene_t)
	BIND_PROPERTY(scene_t,FOV,angle);
	BIND_PROPERTY(scene_t,renderPlaneDist,float);
PROPERTY_BINDING_END

scene_t::scene_t()
{
	FOV=DEG2RAD*50;
	renderPlaneDist=20;
}

void scene_t::initrecursive()
{
	for (entity_t* ptr=this; ptr; ptr=ptr->getnextpo(this))
	{
		if (ptr->activate_at_startup)
			ptr->flags|=ENTITY_TO_BE_ACTIVATED;
		else
			ptr->flags&=~ENTITY_TO_BE_ACTIVATED;

	}
	entity_t::initrecursive();
}

void scene_t::exitrecursive()
{
	entity_t::exitrecursive();
#ifdef LEO_DESIGNER
	for (entity_t* ptr=this; ptr; ptr=ptr->getnextpo(this))
	{
		ptr->localmtx=ptr->initiallocalmtx;
		ptr->invalidateworldmtx();
	}
#endif

}



void scene_t::updaterecursive()
{
	entity_t::updaterecursive();
	update_dynamic_scene();
}

void scene_t::init()
{
	generateentitymap();
	entity_t::init();
	dynamic_entity_array.clear();
	to_add.clear();
}

#include "input/input.h"

void scene_t::update()
{
	entity_t::update();

#if 1//ndef LEO_DESIGNER
	if (INPSYS->keyboard.key_down(DIK_NUMPADSTAR))
	{
		this->renderPlaneDist-=0.15f;
	}
	else if (INPSYS->keyboard.key_down(DIK_NUMPADSLASH))
	{
		this->renderPlaneDist+=0.15f;
	}

	this->renderPlaneDist=clamp(this->renderPlaneDist,2.0f,200.0f);
#endif
}

void scene_t::generateentitymap()
{
	entity_map.clear();
	for (entity_t* ptr=this; ptr; ptr=ptr->getnextpo(this))
		entity_map.insert(ptr);
}

entity_ptr_t scene_t::add_dynamic_entity(entity_t* prototype, const float4x4& pos)
{
	entity_t* clone=prototype->clonerecursive();
	clone->initiallocalmtx=pos;
	to_add.push_back(dyn_struct_t(clone,prototype));
	return entity_ptr_t(clone);
}

entity_t* scene_t::add_dynamic_entity_ptr(entity_t* prototype, const float4x4& pos)
{
	entity_t* clone=prototype->clonerecursive();
	clone->initiallocalmtx=pos;
	to_add.push_back(dyn_struct_t(clone,prototype));
	return clone;
}



entity_t* scene_t::getentity(const char* entityname)
{
	stringhash h=stringhash::get(entityname);

	return entity_map.get(h.value);
}

void scene_t::update_dynamic_scene()
{
	for (uint32 n=0; n<to_add.size(); ++n)
	{
		entity_t* clone=to_add[n].cloned;
		if ((clone->parent && !clone->parent->isactive()))
		{
			clone->eraserecursive();
			continue;
		}
		clone->activate();
		for (entity_t* ptr=clone; ptr; ptr=ptr->getnextpo(clone))
			ptr->flags|=ENTITY_DYNAMIC;
		dyn_struct_t* ds=dynamic_entity_array.allocate_place();
		*ds=to_add[n];
	}
	to_add.clear();

	for (dynamic_array_t::iterator it=dynamic_entity_array.begin(); it!=dynamic_entity_array.end(); ++it)
	{
		entity_t* act=it->cloned;
		if (act->flags & ENTITY_ACTIVE)
		{
			if (act->parent)
			{
				act->invalidateworldmtx();

				if (!(act->parent->flags & ENTITY_ACTIVE) && (act->parent->flags & ENTITY_DYNAMIC))
				{
					act->setlocalmtx(act->getworldmtx());
					act->parent=NULL;
				}
			}

			act->updaterecursive();
		}
	}
	for (dynamic_array_t::iterator it=dynamic_entity_array.begin(); it!=dynamic_entity_array.end();)
	{
		dynamic_array_t::iterator nextit=it;
		++nextit;
		entity_t* act=it->cloned;
		if ((act->flags & ENTITY_ACTIVE) && (act->flags & ENTITY_DYNAMIC_ERASE_IF_POSSIBLE))
		{
			bool meghalhat_e=true;
			for (entity_t* ptr=act; ptr; ptr=ptr->isactive() ? ptr->getnextpo(act) : ptr->getnextpo_up(act))
			{
				if (ptr->isactive() && !ptr->is_erasable())
				{
					meghalhat_e=false;
					break;
				}
			}

			if (meghalhat_e)
				act->deactivate();
		}
		if (!(act->flags & ENTITY_ACTIVE))
		{
			act->eraserecursive();
			dynamic_entity_array.deallocate_place(&*it);
		}
		it=nextit;
	}

}

#include "game.h"
#include "script/script.h"
entity_t* getentity(const string& name)
{
	return GAME->scene->getentity(name.c_str());
}
entity_t* getchildentity(entity_t* e,const string& name)
{
	stringhash n=stringhash::get(name);
	for (entity_t* ptr=e->child; ptr; ptr=ptr->getnextpo(e))
	{
		if (ptr->name==n)
			return ptr;
	}

	return NULL;
}

entity_t* get_parent(entity_t* entity)
{
	return entity->parent;
}

void* get_scriptobject(entity_t* entity)
{
	if (entity->script_object)
		((asIScriptObject*)(entity->script_object))->AddRef();
	return entity->script_object;
}

entity_t* get_scene()
{
	return GAME->scene;
}

script_fn_registering_begin(Scene)
register_script_fn("int get_entity(const string& in)",getentity);
register_script_fn("int get_childentity(int,const string& in)",getchildentity);
register_script_fn("int get_scene_entity()",get_scene);
register_script_fn("int get_parent(int p)",get_parent);
register_script_fn("IScriptObject@ get_scriptobject(int)",get_scriptobject);
script_fn_registering_end